package com.szp.springbootvue.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.szp.springbootvue.domain.User;
import com.szp.springbootvue.utils.SecurityResult;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collection;
import java.util.Date;

public class JwtLoginFilter extends AbstractAuthenticationProcessingFilter {

    protected JwtLoginFilter(String defaultFilterProcessesUrl, AuthenticationManager authenticationManager) {
        super(new AntPathRequestMatcher(defaultFilterProcessesUrl));
        setAuthenticationManager(authenticationManager);
    }

    /*从登录参数中提取出用户名密码，然后调用AuthenticationManager.authenticate()方法去进行自动校验*/
    @Override
    public Authentication attemptAuthentication(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws AuthenticationException, IOException, ServletException {
        User user = new ObjectMapper().readValue(httpServletRequest.getInputStream(), User.class);
        System.out.println(user);
        return getAuthenticationManager().authenticate(new UsernamePasswordAuthenticationToken(user.getUsername(),user.getPassword()));
    }

    /*
    *上面的验证成功后来到这里
    * successfulAuthentication方法中将用户角色遍历并用一个 ,连接起来，
    * 然后再利用Jwts去生成token，
    * 按照代码的顺序，生成过程一共配置了四个参数，
    * 分别是用户角色、主题、过期时间以及加密算法和密钥，然后将生成的token写出到客户端*/
    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
        StringBuffer as = getAuthorities(authResult);   //获得当前用户权限信息
        String jwt = creatJwt(as,authResult);           //创建一个jwt
        System.out.println("jwt = " + jwt);
        //将生成的Token存入redis中
        //UserTokenUtil.addUserTokenToRedis(authResult.getName(),jwt);
        SecurityResult.creatReturnMsg(response,jwt);    //将jwt下发给登录用户
    }

    /*校验失败就会来到unsuccessfulAuthentication方法中，在这个方法中返回一个错误提示给客户端即可*/
    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
        SecurityResult.creatReturnMsg(response,"403");
    }

    /**
     * 根据认证类得到用户的权限信息
     * 将权限信息遍历分开，然后用,号连接起来
     * @param authResult spring security认证类
     * @return 字符串形式的权限信息
     */
    public StringBuffer  getAuthorities(Authentication authResult){
        Collection<? extends GrantedAuthority> authorities = authResult.getAuthorities(); //获得用户的权限-角色信息
        System.out.println("用户的权限信息" + authorities);
        StringBuffer as = new StringBuffer();//Stringbuffer读写性能高，线程不安全
        for (GrantedAuthority authority : authorities) {
            as.append(authority.getAuthority()).append(",");
        }
        return as;
    }

    /**
     * 根据权限信息和用户名，创建一个jwt令牌
     * @param as 权限信息
     * @param authResult 用来获得用户名
     * @return jwt令牌
     */
    public String creatJwt(StringBuffer as,Authentication authResult){
        return Jwts.builder()
                .claim("authorities",as)
                .setSubject(authResult.getName())
                .setExpiration(new Date(System.currentTimeMillis() + 10 * 60 * 1000))//10分钟过期
                .signWith(SignatureAlgorithm.HS512,"sang@123") //sang@123服务器密匙
                .compact();

    }




}

